Visual Viewport API
スクリーンキーボードを開いた後の画面サイズが取得できる、webブラウザのAPI
https://gyazo.com/59e5851d06c4e9ad12498fe111eee840
主にiPhone/iPadで、スクリーンキーボードの上にツールバーやステータスバーを実装するのに使う
iOSはスクリーンキーボードを開いてもwindow.innerHeightが変化しない
position: fixedで画面の下端にくっつけている要素がキーボードで隠れてしまう
キーボードを背景透過させてwebページがぼけて見える仕様のせい
ボケすぎてて何も見えないけど
Mobile Keyboard Toolbarで使おうと思ったけどだめだった
iOSでスクリーンキーボードの上、画面下端にツールバーをくっつけたかった
Androidではまったく不要
CSSのposition: fixedとbottom: 0でいい
Androidはスクリーンキーボードを開くとwindow.innerHeightが縮むので
ドキュメント
https://developer.mozilla.org/en-US/docs/Web/API/Window/visualViewport
対応ブラウザ
iOS 13から使える
https://caniuse.com/mdn-api_visualviewport
API
visualViewport.heightやvisualViewport.offsetTop
スクリーンキーボードを除いた大きさと位置が取得できる
window.heightやwindow.offsetTopと同じような感じ
CSSではなくJavaScriptで値を取得し、要素を移動させなければならない
Reactだとこんな感じだが
code:js
const offsetTop = visualViewport.height - 40 + visualViewport.offsetTop;
const style = {
transform: translate(${visualViewport.offsetLeft}px, ${offsetTop}px) scale(${1/visualViewport.scale}) // CSS書いて
}
return (
<div className='bottom-toolbar' style={style}> // styleにセット
画面スクロールなど、適切なイベントを使ってstyleを再セットし続け、ずっとrenderしなおす必要がある
調査した
https://github.com/shokai/visual-viewport-study/
https://shokai.github.io/visual-viewport-study/
Androidはすばらしい出来
全てのvisualViewportの値がfloatでリアルタイムに更新される
iOSはひどい
textareaにカーソルを入れ、スクリーンキーボードを表示している間は
スクロールを完全に止めるまで、scrollイベントが発火しなくなる
visualViewport.offsetTopの反映が遅れる
0.5刻みで、Androidより精度が低い
window.scrollYは遅延がない
しかしこちらはIntegerなのでガタガタになる
なぜ1px未満の細かいスクロールができる端末で、開発者が取得できる座標系が整数なんだろう?
Androidはwindow.scrollYもfloatなのに
特にiOS safariでは、上下スクロールによってアドレスバーの高さが変化するのだが
それがvisualViewport.heightに反映されるタイミングが一瞬遅い
スクリーンキーボードを開いていない場合は反応が速い
iOS Safariのvisual viewport APIは、キーボード開いている間のアドレスバーの高さが2パターンある事を考慮してないので使い物にならない
iPad
Safari Chrome共通
visualViewport.offsetTopの反映が遅い。iOSと同じ
Chrome
スクリーンキーボードの上のパスワードボタンの高さがvisualViewport.heightに含まれていない
これはSafariでは問題ない
結論
こういうのはiOSでは絶対に作れない
スクリーンキーボードの上にツールバーを常に表示し
上下スクロールしてもスクリーンキーボードにぴったりくっついてくるUI
やるならこう
スクロール中は非表示
スクロールが終わったらツールバーを表示する
windowのscrollやresizeイベントを見て、500 msecぐらい静かであったらスクロール完了と見なす
visualViewport.heightとvisualViewport.offsetTopを使って表示位置を計算する
Mobile Keyboard Toolbarではとりあえずこうする予定shokai.icon
iOSのために作られたAPIだが、iOSはまともに実装されていない
Androidではまったく必要の無いAPIだが、完璧に実装されている